//此文件用于非demo模式下

package common

import (
	"bufio"
	"bytes"
	"xlog/color"

	//"encoding/json"
	"fmt"
	"os"
	"regexp"
	"sort"
	"strconv"
	"strings"
	"xlog/ip2region"
	//"xlog/qqwry"
)

//var qqW qqwry.QQwry
//var ip2region.FindIp()

// func init() {
// 	qqW = qqwry.NewQQwry()
// }

// 访问日志数据结构, 表示访问日志的逻辑结构
type Log struct {
	RemoteAddr      string
	CremoteAddr     string //RemoteAddr ip的C段统计
	XRealIP         string // Header中的RealIP, Nginx会设置
	XRealcIP        string // RealIP 的C段
	Host            string // Header中的Host, 一般会是域名
	Session         string // Passport登录cookie: common_session_id
	TimeLocal       string
	Minute          string // 时间的分钟, HH:mm, 例如12:31, 03:58
	Method          string // GET POST HEAD OPTIONS PUT DELETE ...
	Uri             string
	Version         string // HTTP/1.0, HTTP/1.1 ...
	StatusCode      int64
	BodyBytes       int64
	TimeSeconds     float64 // 响应时间, 单位为秒
	Referer         string
	UserAgent       string
	UriPattern      string  // Uri模式, 将连续数字替换为[0-9]
	RawUri          string  // 不带参数的URL
	XForwardFor     string  // Header中的X-ForwardFor
	BackHost        string  // 可能多个, 逗号加空格分隔
	BackStatus      string  // 可能多个, 逗号加空格分隔
	BackTimeSeconds float64 // 可能多个, 逗号加空格分隔
	LocalAddr       string  // Nginx本机地址
	HitStatus       string  //cache server hit status
	Scheme          string  //scheme
	Province        string  //省
	City            string  //市
	NetOperator     string  //网络运营商
}

// 获取分组值
func (l *Log) Groupby(fields []string) string {
	var buf bytes.Buffer
	for _, f := range fields {
		switch f {
		case "RemoteAddr", "h":
			buf.WriteString(l.RemoteAddr)
			buf.WriteRune(':')
		case "CremoteAddr", "n":
			buf.WriteString(l.CremoteAddr)
			buf.WriteRune(':')
		case "XRealIP", "R":
			buf.WriteString(l.XRealIP)
			buf.WriteRune(':')
		case "XRealcIP", "CR":
			buf.WriteString(l.XRealcIP)
			buf.WriteRune(':')
		case "XForwardFor", "x":
			buf.WriteString(l.XForwardFor)
			buf.WriteRune(':')
		case "UserAgent", "a":
			buf.WriteString(l.UserAgent)
			buf.WriteRune(':')
		case "Referer", "e":
			buf.WriteString(l.Referer)
			buf.WriteRune(':')
		case "Method", "m":
			buf.WriteString(l.Method)
			buf.WriteRune(':')
		case "BackHost", "U":
			buf.WriteString(l.BackHost)
			buf.WriteRune(':')
		case "BackStatus", "S":
			buf.WriteString(l.BackStatus)
			buf.WriteRune(':')
		case "BackTimeSeconds", "z":
			//buf.WriteString(fmt.Sprintf("%f", l.BackTimeSeconds))
			buf.WriteString(l.TimeDist("z"))
			buf.WriteRune(':')
		case "LocalAddr", "l":
			buf.WriteString(l.LocalAddr)
			buf.WriteRune(':')
		case "UriPattern", "p":
			buf.WriteString(l.UriPattern)
			buf.WriteRune(':')
		case "Uri", "r":
			buf.WriteString(l.Uri)
			buf.WriteRune(':')
		case "RawUri", "i":
			buf.WriteString(l.RawUri)
			buf.WriteRune(':')
		case "StatusCode", "s":
			buf.WriteString(strconv.FormatInt(l.StatusCode, 10))
			buf.WriteRune(':')
		case "Host", "H":
			buf.WriteString(l.Host)
			buf.WriteRune(':')
		case "Session", "c":
			buf.WriteString(l.Session)
			buf.WriteRune(':')
		case "Version", "v":
			buf.WriteString(l.Version)
			buf.WriteRune(':')
		case "HitStatus", "k":
			buf.WriteString(l.HitStatus)
			buf.WriteRune(':')
		case "TimeDist", "t":
			buf.WriteString(l.TimeDist("t"))
			buf.WriteRune(':')
		case "Scheme", "w":
			buf.WriteString(l.Scheme)
			buf.WriteRune(':')
		case "Province", "pro":
			buf.WriteString(l.Province)
			buf.WriteRune(':')
		case "City", "city":
			buf.WriteString(l.City)
			buf.WriteRune(':')
		case "NetOperator", "net":
			buf.WriteString(l.NetOperator)
			buf.WriteRune(':')
		}

	}
	return buf.String()
}

// 获取制定时间的分布
func (l *Log) TimeDist(xt string) string {
	var Xtime float64
	if xt == "z" {
		Xtime = l.BackTimeSeconds
	} else if xt == "t" {
		Xtime = l.TimeSeconds
	}
	switch {
	//case Xtime < 0.05000001:
	//	return "<0.05"
	case Xtime < 0.10000001:
		//return "0.05-0.1"
		return "<0.1"
	//case Xtime < 0.20000001:
	//	return "0.1-0.2"
	case Xtime < 0.30000001:
		//return "0.2-0.3"
		return "0.1-0.3"
	//case Xtime < 0.50000001:
	//	return "0.3-0.5"
	case Xtime < 1.00000001:
		//return "0.5-1"
		return "0.3-1"
	case Xtime < 3.00000001:
		return "1-3"
	case Xtime < 5.00000001:
		return "3-5"
	case Xtime < 10.00000001:
		return "5-10"
	//case Xtime < 20.00000001:
	//	return "10-20"
	//case Xtime < 30.00000001:
	//	return "20-30"
	default:
		return ">10"
	}
}

// 显示一行日志, column指定要显示的字段
func (l *Log) DisplayColumn(column string, line string, no int64, showNo bool) {
	if column == "" {
		//column = "XRealIP,TimeLocal,Method,Uri,StatusCode,BodyBytes,TimeSeconds,Referer,UserAgent"
		if showNo {
			color.Cyan("%6d ", no)
			fmt.Print(line)
		} else {
			fmt.Print(line)
		}
		return
	}
	cs := strings.Split(column, ",")
	for i, c := range cs {
		if i > 0 {
			fmt.Print(", ")
		} else {
			if showNo {
				color.Cyan("%6d ", no)
			}
		}
		switch c {
		case "TimeLocal", "T":
			fmt.Print(l.TimeLocal)
		case "RemoteAddr", "h":
			fmt.Print(l.RemoteAddr)
		case "CremoteAddr", "n":
			fmt.Print(l.CremoteAddr)
		case "XRealIP", "R":
			fmt.Print(l.XRealIP)
		case "XRealcIP", "CR":
			fmt.Print(l.XRealcIP)
		case "Method", "m":
			fmt.Print(l.Method)
		case "Uri", "r":
			fmt.Print(l.Uri)
		case "Referer", "e":
			fmt.Print(l.Referer)
		case "UriPattern", "p":
			fmt.Print(l.UriPattern)
		case "RawUri", "i":
			fmt.Print(l.RawUri)
		case "StatusCode", "s":
			fmt.Print(l.StatusCode)
		case "BodyBytes", "b":
			fmt.Print(l.BodyBytes)
		case "TimeSeconds", "t":
			fmt.Print(l.TimeSeconds)
		case "XForwardFor", "x":
			fmt.Print(l.XForwardFor)
		case "UserAgent", "a":
			fmt.Print(l.UserAgent)
		case "BackHost", "U":
			fmt.Print(l.BackHost)
		case "BackStatus", "S":
			fmt.Print(l.BackStatus)
		case "Session", "c":
			fmt.Print(l.Session)
		case "Version", "v":
			fmt.Print(l.Version)
		case "HitStatus", "k":
			fmt.Print(l.HitStatus)
		case "Host", "H":
			fmt.Print(l.Host)
		case "BackTimeSeconds", "z":
			fmt.Print(l.BackTimeSeconds)
		case "LocalAddr", "l":
			fmt.Print(l.LocalAddr)
		case "Scheme", "w":
			fmt.Print(l.Scheme)
		case "Province", "pro":
			fmt.Print(l.Province)
		case "City", "city":
			fmt.Print(l.City)
		case "NetOperator", "net":
			fmt.Print(l.NetOperator)
		}
	}
	fmt.Println()
}

// 以json格式显示一行日志, column指定要显示的字段,
func (l *Log) DisplayColumnJson(column string, line string, no int64, showNo bool) {
	if column == "" {
		//column = "XRealIP,TimeLocal,Method,Uri,StatusCode,BodyBytes,TimeSeconds,Referer,UserAgent"
		// parser := NewLogParser("")
		// log := parser.ParseLogJson(line)
		// b, err := json.Marshal(log)
		// if err != nil {
		// 	fmt.Printf("JsonMarshalErr:%s\n", err)
		// 	return
		// }
		fmt.Println(line)
		return
	}

	fmt.Print("{")
	cs := strings.Split(column, ",")
	for i, c := range cs {
		if i > 0 {
			fmt.Print(",")
		}
		switch c {
		case "TimeLocal", "T":
			fmt.Print(l.TimeLocal)
		case "RemoteAddr", "h":
			fmt.Print(l.RemoteAddr)
		case "CremoteAddr", "n":
			fmt.Print(l.CremoteAddr)
		case "XRealIP", "R":
			fmt.Print(l.XRealIP)
		case "XRealcIP", "CR":
			fmt.Print(l.XRealcIP)
		case "Method", "m":
			fmt.Print(l.Method)
		case "Uri", "r":
			fmt.Print(l.Uri)
		case "Referer", "e":
			fmt.Print(l.Referer)
		case "UriPattern", "p":
			fmt.Print(l.UriPattern)
		case "RawUri", "i":
			fmt.Print(l.RawUri)
		case "StatusCode", "s":
			fmt.Print(l.StatusCode)
		case "BodyBytes", "b":
			fmt.Print(l.BodyBytes)
		case "TimeSeconds", "t":
			fmt.Print(l.TimeSeconds)
		case "XForwardFor", "x":
			fmt.Print(l.XForwardFor)
		case "UserAgent", "a":
			fmt.Print(l.UserAgent)
		case "BackHost", "U":
			fmt.Print(l.BackHost)
		case "BackStatus", "S":
			fmt.Print(l.BackStatus)
		case "Session", "c":
			fmt.Print(l.Session)
		case "Version", "v":
			fmt.Print(l.Version)
		case "HitStatus", "k":
			fmt.Print(l.HitStatus)
		case "Host", "H":
			fmt.Print(l.Host)
		case "BackTimeSeconds", "z":
			fmt.Print(l.BackTimeSeconds)
		case "LocalAddr", "l":
			fmt.Print(l.LocalAddr)
		case "Scheme", "w":
			fmt.Print(l.Scheme)
		case "Province", "pro":
			fmt.Print(l.Province)
		case "City", "city":
			fmt.Print(l.City)
		case "NetOperator", "net":
			fmt.Print(l.NetOperator)
		}
	}
	fmt.Print("}")
	fmt.Println()
}

// 用于解析访问日志的解析器
type LogParser struct {
	logPattern *regexp.Regexp
}

// 日志解析器的构造函数, 参数为正则式编号会从xlog.cfg文件加载正则式, 参数为空串会使用内置
// 方法解析固定格式的resin或者nginx的访问日志
func NewLogParser(patternId string) (parser *LogParser) {
	if patternId != "" {
		file, err := os.Open("/etc/xlog/xlog.cfg")
		if err != nil {
			//return nil
			fmt.Println("open /etc/xlog/xlog.cfg failure!")
			os.Exit(-1)
		}
		defer file.Close()
		scanner := bufio.NewScanner(file)
		for scanner.Scan() {
			line := scanner.Text()
			key := fmt.Sprintf("%s=", patternId)
			if strings.HasPrefix(line, key) {
				parser = &LogParser{
					logPattern: regexp.MustCompile(line[len(key):]),
				}
				break
			}
		}
	}
	if parser == nil {
		parser = &LogParser{}
	}
	return
}

// 计算Uri模式
func uri2Pattern(uri string) string {
	var buf bytes.Buffer
	runes := []rune(uri)
	last := '/'
	for _, r := range runes {
		if r >= '0' && r <= '9' {
			if last < '0' || last > '9' {
				buf.WriteString("[0-9]")
			}
		} else {
			buf.WriteRune(r)
		}

		last = r
	}
	return buf.String()
}

// 计算RawUri模式
func uri2RawUri(uri string) string {
	var buf bytes.Buffer
	if strings.Contains(uri, "?") {
		buf.WriteString(string(strings.Split(uri, "?")[0]))
	} else {
		buf.WriteString(uri)
	}
	return buf.String()
}

//获取remoteaddress的C段
func Radd2Cradd(addr string) string {
	raddr := strings.Split(addr, ".")
	if len(raddr) > 3 {
		return fmt.Sprintf("%s.%s.%s", raddr[0], raddr[1], raddr[2])
	} else {
		//fmt.Println(raddr)
		return addr
	}

}

// 私有函数, 使用正则式解析日志, 扩展性好, 速度很慢
func (p *LogParser) parseLogWithPattern(line string) (l *Log) {
	match := p.logPattern.FindStringSubmatch(line)
	if match == nil {
		fmt.Printf("NOT MATCH: %s\n", line)
		return nil
	}

	l = &Log{}
	for i, name := range p.logPattern.SubexpNames() {
		if i == 0 || name == "" {
			continue
		}
		switch name {
		case "RemoteAddr", "h":
			l.RemoteAddr = match[i]
			l.CremoteAddr = Radd2Cradd(match[i])
		case "XRealIP", "R":
			l.XRealIP = match[i]
		case "XRealcIP", "CR":
			l.XRealcIP = Radd2Cradd(match[i])
		case "TimeLocal", "T":
			l.TimeLocal = match[i]
			l.Minute = match[i][12:17]
		case "Uri", "r":
			//requestLine := strings.SplitN(match[i], " ", 3)
			//if len(requestLine) < 3 {
			//	requestLine = []string{"\"", "", "\""}
			//}
			//l.Method = requestLine[0]
			//l.Uri = requestLine[1]
			l.Uri = match[i]
			l.UriPattern = uri2Pattern(l.Uri)
			l.RawUri = uri2RawUri(l.Uri)
			//l.Version = requestLine[2]
		case "StatusCode", "s":
			l.StatusCode, _ = strconv.ParseInt(match[i], 10, 64)
		case "BodyBytes", "B":
			l.BodyBytes, _ = strconv.ParseInt(match[i], 10, 64)
		case "TimeSeconds", "t":
			l.TimeSeconds, _ = strconv.ParseFloat(match[1], 64)
		case "TimeMicroSeconds":
			l.TimeSeconds, _ = strconv.ParseFloat(match[i], 64)
			l.TimeSeconds = l.TimeSeconds / 1000000
		case "TimeMilliSeconds":
			l.TimeSeconds, _ = strconv.ParseFloat(match[i], 64)
			l.TimeSeconds = l.TimeSeconds / 1000
		case "Referer", "e":
			l.Referer = match[i]
		case "AtsUri":
			requestLine := strings.SplitN(match[i], "/", 4)
			if len(requestLine) < 4 {
				requestLine = []string{"", "", "", ""}
				l.Uri = match[i]
				l.Host = match[i]
			} else {
				l.Uri = fmt.Sprintf("/%s", requestLine[3])
				l.Host = requestLine[2]
			}
			l.UriPattern = uri2Pattern(l.Uri)
			l.RawUri = uri2RawUri(l.Uri)
		case "UserAgent", "a":
			l.UserAgent = match[i]
		case "Host", "H":
			l.Host = match[i]
		case "Method", "m":
			l.Method = match[i]
		case "XForwardFor", "x":
			l.XForwardFor = match[i]
		case "BackHost", "U":
			l.BackHost = match[i]
		case "BackStatus", "S":
			l.BackStatus = match[i]
		case "HitStatus", "k":
			l.HitStatus = match[i]
		case "BackTimeSeconds", "z":
			//l.BackTimeSeconds = match[i]
			var backTs float64 = 0
			if strings.IndexRune(match[i], ',') > 1 {
				for _, s := range strings.Split(match[i], ", ") {
					t, _ := strconv.ParseFloat(s, 64)
					backTs = backTs + t
				}
			} else {
				backTs, _ = strconv.ParseFloat(match[i], 64)
			}
			l.TimeSeconds = backTs
		case "LocalAddr", "l":
			l.LocalAddr = match[i]
		default:
			//println(name)
		}
	}
	return
}

// 内置硬编码解析Resin的accesslog, 比缺省的日志增加了RealIP和响应时间
func (p *LogParser) parseResinLog(line string) (l *Log) {
	fields := strings.SplitN(line, " ", 14)
	if len(fields) < 14 {
		fmt.Println(line)
		return nil
	}
	sc, _ := strconv.ParseInt(fields[9], 10, 64)
	bb, _ := strconv.ParseInt(fields[10], 10, 64)
	tn, _ := strconv.ParseFloat(fields[11], 64)
	var ref string = fields[12]
	ll := len(ref)
	if strings.HasPrefix(ref, "\"http://") || ll > 3 {
		ref = ref[1 : ll-1]
	} else {
		ref = "-"
	}
	last := fields[13][1:]
	pos := strings.IndexRune(last, '"')
	xf := last[:pos]

	var xrip string
	if strings.Count(xf, ".") >= 3 {
		xrip = strings.FieldsFunc(xf, Spiltfunc)[0]
		if strings.HasPrefix(xrip, "192.168.") || strings.HasPrefix(xrip, "172.16.") || strings.HasPrefix(xrip, "10.") {
			xriparr := strings.FieldsFunc(xf, Spiltfunc)
			if len(xriparr) > 1 {
				xrip = xriparr[1]
			} else {
				xrip = fields[0]
			}
		}
	} else {
		xrip = fields[0]
	}

	var ua string
	if len(last)-2 > pos+3 {
		ua = last[pos+3 : len(last)-2]
	} else {
		ua = "-"
	}

	l = &Log{
		RemoteAddr:  fields[0],
		CremoteAddr: Radd2Cradd(fields[0]),
		//XRealIP:     fields[1],
		XRealIP:     xrip,
		XRealcIP:    Radd2Cradd(xrip),
		Session:     fields[3],
		TimeLocal:   fields[4][1:],
		Method:      fields[6][1:],
		Uri:         fields[7],
		Version:     fields[8][:len(fields[8])-1],
		StatusCode:  sc,
		BodyBytes:   bb,
		TimeSeconds: tn / 1000000,
		Referer:     ref,
		UriPattern:  uri2Pattern(fields[7]),
		RawUri:      uri2RawUri(fields[7]),
		XForwardFor: xf,
		UserAgent:   ua,
	}

	l.Minute = l.TimeLocal[12:17]

	return
}

func Spiltfunc(s rune) bool {
	if s == ',' || s == '"' || s == ' ' {
		return true
	} else {
		return false
	}
}

// 内置硬编码解析Nginx的accesslog, 按照现在使用的约定格式
func (p *LogParser) parseNginxLog(line string) (l *Log) {
	fields := strings.Split(line, " | ")
	lenth := len(fields)
	if lenth < 13 {
		fmt.Println(line)
		return nil
	}
	requestLine := strings.SplitN(fields[3], " ", 3)
	if len(requestLine) < 3 {
		requestLine = []string{"\"", "", "\""}
	}
	sc, _ := strconv.ParseInt(fields[4], 10, 64)
	bb, _ := strconv.ParseInt(fields[5], 10, 64)
	var ref string = fields[6]
	ll := len(ref)
	if strings.HasPrefix(ref, "\"http://") || ll > 3 {
		ref = ref[1 : ll-1]
	} else {
		ref = "-"
	}
	var backTs float64 = 0
	var reqTs float64 = 0

	var xrip string
	if strings.Count(fields[8], ".") >= 3 {
		xrip = strings.FieldsFunc(fields[8], Spiltfunc)[0]
		if strings.HasPrefix(xrip, "192.168.") || strings.HasPrefix(xrip, "172.16.") || strings.HasPrefix(xrip, "10.") {
			xriparr := strings.FieldsFunc(fields[8], Spiltfunc)
			if len(xriparr) > 1 {
				xrip = xriparr[1]
			} else {
				xrip = fields[0]
			}
		}
	} else {
		xrip = fields[0]
	}

	if strings.IndexRune(fields[11], ',') > 1 {
		for _, s := range strings.Split(fields[11], ", ") {
			t, _ := strconv.ParseFloat(s, 64)
			backTs = backTs + t
		}
	} else {
		backTs, _ = strconv.ParseFloat(fields[11], 64)
	}
	if lenth < 14 {
		reqTs = backTs
	} else {
		reqTs, _ = strconv.ParseFloat(strings.TrimSpace(fields[13]), 64)
	}

	var sch string
	if lenth < 15 {
		sch = "-"
	} else {
		sch = fields[14]
	}

	var province, city, netoperator string = "-", "-", "-"
	//province = qqwry.Anaxiptoarea(xrip).Province
	//var area *qqwry.Areainfo

	//if ok, _ := qqwry.PathExists(); ok {
	if ok, _ := ip2region.PathExists(); ok {
		//aar := qqW.Anaxiptoarea(xrip)
		// province = aar.Province
		// city = aar.City
		// netoperator = aar.NetOperator
		aar := ip2region.FindIp(xrip)
		province = aar.Province
		city = aar.City
		netoperator = aar.ISP
	}

	l = &Log{
		RemoteAddr: fields[0],
		//RemoteAddr:  strings.Split(fields[0], ":")[0],
		CremoteAddr: Radd2Cradd(fields[0]),
		//XRealIP:         fields[0],
		XRealIP:         xrip,
		XRealcIP:        Radd2Cradd(xrip),
		TimeLocal:       fields[1][1:21],
		Host:            fields[2],
		Method:          requestLine[0][1:],
		Uri:             requestLine[1],
		Version:         requestLine[2][:len(requestLine[2])-1],
		StatusCode:      sc,
		BodyBytes:       bb,
		Referer:         ref,
		BackStatus:      fields[10],
		BackHost:        fields[9],
		BackTimeSeconds: backTs,
		LocalAddr:       fields[12],
		UriPattern:      uri2Pattern(requestLine[1]),
		RawUri:          uri2RawUri(requestLine[1]),
		TimeSeconds:     reqTs,
		UserAgent:       fields[7][1 : len(fields[7])-1],
		XForwardFor:     fields[8][1 : len(fields[8])-1],
		Scheme:          sch,
		Province:        province,
		City:            city,
		NetOperator:     netoperator,
	}
	if len(fields) > 14 {
		//l.Session = fields[14][:len(fields[14])-1]
		if len(fields[14])-1 > 0 {
			l.Session = fields[14][:len(fields[14])-1]
		} else {
			l.Session = ""
		}
	}
	l.Minute = l.TimeLocal[12:17]

	return
}

// 解析单行字符串到日志对象
func (p *LogParser) ParseLog(line string) (l *Log) {
	if strings.TrimRight(line, " \r\n") == "" {
		return nil
	}
	if p.logPattern == nil {
		if strings.Index(line, " | ") > 1 {
			l = p.parseNginxLog(line)
		} else {
			l = p.parseResinLog(line)
		}
	} else {
		l = p.parseLogWithPattern(line)
	}
	return
}

// 解析单行字符串到日志对象
func (p *LogParser) ParseLogJson(line string) (l *Log) {
	if strings.TrimRight(line, " \r\n") == "" {
		return nil
	}
	if p.logPattern == nil {
		if strings.Index(line, " | ") > 1 {
			l = p.parseNginxLog(line)
		} else {
			l = p.parseResinLog(line)
		}
	} else {
		l = p.parseLogWithPattern(line)
	}
	return
}

// 命令行指定的单个过滤条件数据结构
type Filter struct {
	Field string // 字段名
	Oper  string // 比较符号
	Value string // 条件值
}

// 条件构造函数
func NewFilter(str string) (f *Filter) {
	fields := strings.SplitN(str, " ", 3)
	return &Filter{
		Field: fields[0],
		Oper:  fields[1],
		Value: fields[2],
	}
}

// 过滤string类型字段
func (f *Filter) FilterStr(v string) bool {
	switch f.Oper {
	case "=":
		return v == f.Value
	case "!=":
		return v != f.Value
	case ">":
		return v > f.Value
	case "<":
		return v < f.Value
	case ">=":
		return v >= f.Value
	case "<=":
		return v <= f.Value
	case "startWith", "sw":
		return strings.HasPrefix(v, f.Value)
	case "endWith", "ew":
		return strings.HasSuffix(v, f.Value)
	case "contains", "cs":
		return strings.Contains(v, f.Value)
	case "notcontains", "ncs":
		return !strings.Contains(v, f.Value)
	case "regexp", "rp":
		match, _ := regexp.MatchString(f.Value, v)
		return match
		//r, _ := regexp.Compile(f.Value)
		//return r.MatchString(v)
	}
	return false
}

// 过滤整数类型字段
func (f *Filter) FilterInt64(v int64) bool {
	cc, _ := strconv.ParseInt(f.Value, 10, 64)
	switch f.Oper {
	case "=":
		return v == cc
	case "!=":
		return v != cc
	case ">":
		return v > cc
	case "<":
		return v < cc
	case ">=":
		return v >= cc
	case "<=":
		return v <= cc
	case "regexp", "rp":
		match, _ := regexp.MatchString(f.Value, strconv.Itoa(int(v)))
		return match
	case "notcontains", "ncs":
		return !strings.Contains(f.Value, strconv.Itoa(int(v)))
	}
	return false
}

// 过滤float类型字段
func (f *Filter) FilterFloat64(v float64) bool {
	cc, _ := strconv.ParseFloat(f.Value, 64)
	switch f.Oper {
	case "=":
		return v == cc
	case "!=":
		return v != cc
	case ">":
		return v > cc
	case "<":
		return v < cc
	case ">=":
		return v >= cc
	case "<=":
		return v <= cc
	}
	return false
}

// 过滤日志
func (f *Filter) FilterLog(l *Log) bool {
	if l == nil {
		return false
	}

	switch f.Field {
	case "RemoteAddr", "h":
		return f.FilterStr(l.RemoteAddr)
	case "CremoteAddr", "n":
		return f.FilterStr(l.CremoteAddr)
	case "XRealIP", "R":
		return f.FilterStr(l.XRealIP)
	case "XRealcIP", "CR":
		return f.FilterStr(l.XRealcIP)
	case "Host", "H":
		return f.FilterStr(l.Host)
	case "Session", "c":
		return f.FilterStr(l.Session)
	case "TimeLocal", "T":
		return f.FilterStr(l.TimeLocal)
	case "Method", "m":
		return f.FilterStr(l.Method)
	case "Uri", "r":
		return f.FilterStr(l.Uri)
	case "UriPattern", "p":
		return f.FilterStr(l.UriPattern)
	case "RawUri", "i":
		return f.FilterStr(l.RawUri)
	case "Version", "v":
		return f.FilterStr(l.Version)
	case "StatusCode", "s":
		return f.FilterInt64(l.StatusCode)
	case "BodyBytes", "b":
		return f.FilterInt64(l.BodyBytes)
	case "TimeSeconds", "t":
		return f.FilterFloat64(l.TimeSeconds)
	case "Minute", "M":
		return f.FilterStr(l.Minute)
	case "BackTimeSeconds", "z":
		return f.FilterFloat64(l.BackTimeSeconds)
	case "Referer", "e":
		return f.FilterStr(l.Referer)
	case "UserAgent", "a":
		return f.FilterStr(l.UserAgent)
	case "BackHost", "U":
		return f.FilterStr(l.BackHost)
	case "BackStatus", "S":
		return f.FilterStr(l.BackHost)
	case "HitStatus", "k":
		return f.FilterStr(l.HitStatus)
	case "XForwardFor", "x":
		return f.FilterStr(l.XForwardFor)
	case "Scheme", "w":
		return f.FilterStr(l.Scheme)
	case "Province", "pro":
		return f.FilterStr(l.Province)
	case "City", "city":
		return f.FilterStr(l.City)
	case "NetOperator", "net":
		return f.FilterStr(l.NetOperator)
	}

	return false
}

func MatchFilters(filters []*Filter, l *Log, tjf bool) (result bool) {
	if tjf {
		result = false
		for _, f := range filters {
			if f.FilterLog(l) {
				result = true
				break
			}
		}
		return
	} else {
		result = true
		for _, f := range filters {
			if !f.FilterLog(l) {
				result = false
				break
			}
		}
		return
	}
}

// 用于对合计结果进行排序的数据结构
type CountItem struct {
	K string
	V int64
}

// 以字符串形式显示数据项
func (c CountItem) String() string {
	return fmt.Sprintf("%v: %d", c.K, c.V)
}

// 排序数据结构
type ByCount []CountItem

func (c ByCount) Len() int           { return len(c) }
func (c ByCount) Swap(i, j int)      { c[i], c[j] = c[j], c[i] }
func (c ByCount) Less(i, j int) bool { return c[i].V > c[j].V }

// 排序并打印合计的数据项字典
func PrintMap(m map[string]int64, base int64, top int, isbytes bool) {
	var bc ByCount = make([]CountItem, 0, len(m))
	for k, v := range m {
		bc = append(bc, *&CountItem{k, v})
	}
	sort.Sort(bc)
	for i, v := range bc {

		if isbytes {
			color.Yellow("\t%d ", v.V)
			color.Green("%.3f%%, ", float64(v.V)/float64(base)*100)
			fmt.Printf("%s\n", strings.TrimRight(v.K, ":"))
		} else {
			color.Yellow("\t%d ", v.V)
			color.Green("%.3f%%, ", float64(v.V)/float64(base)*100)
			fmt.Printf("%s\n", strings.TrimRight(v.K, ":"))
		}
		if i > top {
			break
		}
	}
	l := len(bc)
	if l > top {
		fmt.Printf("\t-- %d of %d is hidden\n", l-top, l)
	}
}

func highLight(name string) bool {
	return name == "400" ||
		name == "404" ||
		name == "500" ||
		name == "502" ||
		name == "503" ||
		name == "504" ||
		name == ">30" ||
		name == "20-30" ||
		name == "10-20" ||
		name == "5-10" ||
		name == "3-5" ||
		name == "1-3" ||
		name == "0.5-1"
}

// 排序并打印合计的数据字典, 两个字典并排显示, 对于特殊的数据项名称套红
func PrintMap2(m1 map[string]int64, base1 int64, m2 map[string]int64, base2 int64) {
	var bc1 ByCount = make([]CountItem, 0, len(m1))
	for k, v := range m1 {
		bc1 = append(bc1, *&CountItem{k, v})
	}
	sort.Sort(bc1)
	var bc2 ByCount = make([]CountItem, 0, len(m2))
	for k2, v2 := range m2 {
		bc2 = append(bc2, *&CountItem{k2, v2})
	}
	sort.Sort(bc1)
	sort.Sort(bc2)
	l1 := len(bc1)
	l2 := len(bc2)
	for i, v := range bc1 {
		if highLight(v.K) {
			color.Red("%15s ", v.K)
			color.Yellow("%10d, ", v.V)
			color.Green("%.3f%%", float64(v.V)/float64(base1)*100)
		} else {
			fmt.Printf("%15s ", v.K)
			color.Yellow("%10d, ", v.V)
			color.Green("%.3f%%", float64(v.V)/float64(base1)*100)
		}
		if i < l2 {
			v2 := bc2[i]
			if highLight(v2.K) {
				color.Red("\t\t%15s ", v2.K)
				color.Yellow("%10d, ", v2.V)
				color.Green("%.3f%%\n", float64(v2.V)/float64(base2)*100)
			} else {
				fmt.Printf("\t\t%15s ", v2.K)
				color.Yellow("%10d, ", v2.V)
				color.Green("%.3f%%\n", float64(v2.V)/float64(base2)*100)
			}
		} else {
			fmt.Println()
		}
		if i > 20 {
			break
		}
	}
	if l1 > 20 {
		fmt.Printf("--%10d of %10d is hidden", l1-20, l1)
		if l2 > 20 {
			fmt.Printf("\t\t--%10d of %10d is hidden\n", l2-20, l2)
		} else {
			fmt.Println()
		}
	}
}

// 计数器对象
type Counter struct {
	Map map[string]int64
}

// 新建计数器对象实例
func NewCounter() *Counter {
	return &Counter{
		Map: make(map[string]int64, 60),
	}
}

// 对制定key进行计数
func (c *Counter) Count(k string) {
	v, ok := c.Map[k]
	if ok {
		mutex.Lock()
		defer mutex.Unlock()
		c.Map[k] = v + 1
	} else {
		mutex.Lock()
		defer mutex.Unlock()
		c.Map[k] = 1
	}
}

//统计指定字段发送字节的大小
func (c *Counter) CountBytes(l *Log, k string) {
	//k := log.Host
	v, ok := c.Map[k]
	if ok {
		mutex.Lock()
		defer mutex.Unlock()
		c.Map[k] = v + l.BodyBytes
	} else {
		mutex.Lock()
		defer mutex.Unlock()
		c.Map[k] = l.BodyBytes
	}
	//fmt.Println(k, ok)
}

type TrendCounter struct {
	MapC    map[string]int64
	MapT    map[string]float64
	MapMaxT map[string]float64
	MapB    map[string]int64
	MapIp   map[string]int64
	Map200  map[string]int64
	Map301  map[string]int64
	Map302  map[string]int64
	Map400  map[string]int64
	Map403  map[string]int64
	Map404  map[string]int64
	Map499  map[string]int64
	Map500  map[string]int64
	Map502  map[string]int64
	Map503  map[string]int64
	Map504  map[string]int64

	MapBaiduspider map[string]int64
	MapSpider360   map[string]int64
	MapSogouspider map[string]int64
	MapGooglebot   map[string]int64
	MapSosospider  map[string]int64
	MapYisouSpider map[string]int64

	MapUCBrowser      map[string]int64
	MapMicroMessenger map[string]int64
	MapMQQBrowser     map[string]int64
	//MapAndroid        map[string]int64
	//MapiPhone        map[string]int64

	MapMaxthon   map[string]int64
	MapQQBrowser map[string]int64
	MapLBBROWSER map[string]int64
	MapSE360     map[string]int64

	Mapmsie    map[string]int64
	Mapchrome  map[string]int64
	Mapfirefox map[string]int64
	Mapsafari  map[string]int64
	MapOtherUa map[string]int64
}

func NewTrendCounter() (c *TrendCounter) {
	c = &TrendCounter{
		MapC:    make(map[string]int64, 60),
		MapT:    make(map[string]float64, 60),
		MapMaxT: make(map[string]float64, 60),
		MapB:    make(map[string]int64, 60),
		MapIp:   make(map[string]int64, 60),
		Map200:  make(map[string]int64, 60),
		Map301:  make(map[string]int64, 60),
		Map302:  make(map[string]int64, 60),
		Map400:  make(map[string]int64, 60),
		Map403:  make(map[string]int64, 60),
		Map404:  make(map[string]int64, 60),
		Map499:  make(map[string]int64, 60),
		Map500:  make(map[string]int64, 60),
		Map502:  make(map[string]int64, 60),
		Map503:  make(map[string]int64, 60),
		Map504:  make(map[string]int64, 60),

		MapBaiduspider: make(map[string]int64, 60),
		MapSpider360:   make(map[string]int64, 60),
		MapSogouspider: make(map[string]int64, 60),
		MapGooglebot:   make(map[string]int64, 60),
		MapSosospider:  make(map[string]int64, 60),
		MapYisouSpider: make(map[string]int64, 60),

		MapUCBrowser:      make(map[string]int64, 60),
		MapMicroMessenger: make(map[string]int64, 60),
		MapMQQBrowser:     make(map[string]int64, 60),
		//MapAndroid:        make(map[string]int64, 60),
		//MapiPhone:         make(map[string]int64, 60),

		MapMaxthon:   make(map[string]int64, 60),
		MapQQBrowser: make(map[string]int64, 60),
		MapLBBROWSER: make(map[string]int64, 60),
		MapSE360:     make(map[string]int64, 60),

		Mapmsie:    make(map[string]int64, 60),
		Mapchrome:  make(map[string]int64, 60),
		Mapfirefox: make(map[string]int64, 60),
		Mapsafari:  make(map[string]int64, 60),
		MapOtherUa: make(map[string]int64, 60),
	}
	return
}

//统计独立ip数量
var IpMap = make(map[string]string)

//统计多个URI的请求分布
var UriMap = make(map[string]map[string]int64)
var umap = make(map[string]int64)

func (c *TrendCounter) Count(log *Log, t, tendargs string) {
	mutex.Lock()
	defer mutex.Unlock()
	var k string
	IpMap["127.0.0.1"] = "1"
	switch t {
	case "m":
		k = log.TimeLocal[12:17]
	case "s":
		k = log.TimeLocal[12:20]
	case "hour":
		//k = log.TimeLocal[0:14]
		k = log.TimeLocal[0:2] + "/" + log.TimeLocal[12:14]
	case "d":
		//k = log.TimeLocal[0:11]
		k = log.TimeLocal[0:6]
	case "r":
		k = log.Uri
	case "a":
		k = log.UserAgent
	case "e":
		k = log.Referer
	case "h":
		k = log.RemoteAddr
	case "i":
		k = log.RawUri
	case "U":
		k = log.BackHost
	case "x":
		k = log.XForwardFor
	case "R":
		k = log.XRealIP
	case "CR":
		k = log.XRealcIP
	case "n":
		k = log.CremoteAddr
	case "w":
		k = log.Scheme
	case "H":
		k = log.Host
	case "md":
		k = log.Method
	default:
		fmt.Println("Trend arugs no support " + t)
		os.Exit(1)
	}

	v, ok := c.MapC[k]
	if ok {
		c.MapC[k] = v + 1
	} else {
		c.MapC[k] = 1
	}

	//统计UserAgent
	if tendargs == "ua" {
		Baiduspider, ok := c.MapBaiduspider[k]
		Spider360, _ := c.MapSpider360[k]
		Sogouspider, _ := c.MapSogouspider[k]
		Googlebot, _ := c.MapGooglebot[k]
		Sosospider, _ := c.MapSosospider[k]
		YisouSpider, _ := c.MapYisouSpider[k]

		UCBrowser, _ := c.MapUCBrowser[k]
		MicroMessenger, _ := c.MapMicroMessenger[k]
		MQQBrowser, _ := c.MapMQQBrowser[k]
		Maxthon, _ := c.MapMaxthon[k]
		QQBrowser, _ := c.MapQQBrowser[k]
		LBBROWSER, _ := c.MapLBBROWSER[k]
		SE360, _ := c.MapSE360[k]

		msie, _ := c.Mapmsie[k]
		chrome, _ := c.Mapchrome[k]
		firefox, _ := c.Mapfirefox[k]
		safari, _ := c.Mapsafari[k]
		OtherUa, _ := c.MapOtherUa[k]

		if ok {
			switch {
			//爬虫，由于存在包含关系，需要严格按照顺序爬虫ua--移动端[uc|android|ios]---tx,360,liebao---pc端[chrome,msie,firefox,safari]
			case strings.Contains(log.UserAgent, "Baiduspider"):
				c.MapBaiduspider[k] = Baiduspider + 1
			case strings.Contains(log.UserAgent, "360Spider"):
				c.MapSpider360[k] = Spider360 + 1
			case strings.Contains(log.UserAgent, "Sogou web spider"):
				c.MapSogouspider[k] = Sogouspider + 1
			case strings.Contains(log.UserAgent, "Googlebot"):
				c.MapGooglebot[k] = Googlebot + 1
			case strings.Contains(log.UserAgent, "Sosospider"):
				c.MapSosospider[k] = Sosospider + 1
			case strings.Contains(log.UserAgent, "YisouSpider"):
				c.MapYisouSpider[k] = YisouSpider + 1
				//移动浏览器
			case strings.Contains(log.UserAgent, "UCBrowser"):
				c.MapUCBrowser[k] = UCBrowser + 1
			case strings.Contains(log.UserAgent, "MicroMessenger"):
				c.MapMicroMessenger[k] = MicroMessenger + 1
			case strings.Contains(log.UserAgent, "MQQBrowser"):
				c.MapMQQBrowser[k] = MQQBrowser + 1
				//pc浏览器
			case strings.Contains(log.UserAgent, "Maxthon"):
				c.MapMaxthon[k] = Maxthon + 1
			case strings.Contains(log.UserAgent, "QQBrowser"):
				c.MapQQBrowser[k] = QQBrowser + 1
			case strings.Contains(log.UserAgent, "LBBROWSER"):
				c.MapLBBROWSER[k] = LBBROWSER + 1
			case strings.Contains(log.UserAgent, "360SE") || strings.Contains(log.UserAgent, "360EE"): //360浏览会屏蔽自己的标识
				c.MapSE360[k] = SE360 + 1

			case strings.Contains(log.UserAgent, "MSIE"):
				c.Mapmsie[k] = msie + 1
			case strings.Contains(log.UserAgent, "Chrome"):
				c.Mapchrome[k] = chrome + 1
			case strings.Contains(log.UserAgent, "Firefox"):
				c.Mapfirefox[k] = firefox + 1
			case strings.Contains(log.UserAgent, "Safari"):
				c.Mapsafari[k] = safari + 1
			default:
				c.MapOtherUa[k] = OtherUa + 1
			}
		} else {
			//爬虫
			c.MapBaiduspider[k] = 0
			c.MapSpider360[k] = 0
			c.MapSogouspider[k] = 0
			c.MapGooglebot[k] = 0
			c.MapSosospider[k] = 0
			c.MapYisouSpider[k] = 0
			//移动浏览器
			c.MapUCBrowser[k] = 0
			c.MapMicroMessenger[k] = 0
			c.MapMQQBrowser[k] = 0
			//pc浏览器
			c.MapMaxthon[k] = 0
			c.MapQQBrowser[k] = 0
			c.MapLBBROWSER[k] = 0

			c.Mapmsie[k] = 0
			c.Mapchrome[k] = 0
			c.Mapfirefox[k] = 0
			c.Mapsafari[k] = 0
			c.MapOtherUa[k] = 0
		}
	}

	//统计uri的分布，通过长度来区别与ua和sc等参数
	if len(tendargs) > 4 {
		uriarry := strings.Split(tendargs, ",")
		//var ok bool
		for i := 0; i < len(uriarry); i++ {
			urikey := "uri" + strconv.Itoa(i)
			//matchuri, _ := regexp.MatchString(uriarry[i], log.Uri)
			ookk := strings.Contains(log.Uri, uriarry[i])
			//if matchuri {
			if ookk {
				_, ok := UriMap[k]
				if ok {
					UriMap[k][urikey] = UriMap[k][urikey] + 1
				} else {
					umap := make(map[string]int64)
					umap[urikey] = 0
					UriMap[k] = umap
				}
			}
		}
	}

	//使用-sc参数或者不使用参数时统计状态码、时间，字节等
	if tendargs == "sc" || tendargs == "" {
		//统计状态码
		vs200, ok := c.Map200[k]
		vs301, _ := c.Map301[k]
		vs302, _ := c.Map302[k]
		vs400, _ := c.Map400[k]
		vs403, _ := c.Map403[k]
		vs404, _ := c.Map404[k]
		vs499, _ := c.Map499[k]
		vs500, _ := c.Map500[k]
		vs502, _ := c.Map502[k]
		vs503, _ := c.Map503[k]
		vs504, _ := c.Map504[k]

		if ok {
			switch log.StatusCode {
			case 200:
				c.Map200[k] = vs200 + 1
			case 301:
				c.Map301[k] = vs301 + 1
			case 302:
				c.Map302[k] = vs302 + 1
			case 400:
				c.Map400[k] = vs400 + 1
			case 403:
				c.Map403[k] = vs403 + 1
			case 404:
				c.Map404[k] = vs404 + 1
			case 499:
				c.Map499[k] = vs499 + 1
			case 500:
				c.Map500[k] = vs500 + 1
			case 502:
				c.Map502[k] = vs502 + 1
			case 503:
				c.Map503[k] = vs503 + 1
			case 504:
				c.Map504[k] = vs504 + 1
			}
		} else {
			c.Map200[k] = 0
			c.Map301[k] = 0
			c.Map302[k] = 0
			c.Map403[k] = 0
			c.Map400[k] = 0
			c.Map404[k] = 0
			c.Map499[k] = 0
			c.Map500[k] = 0
			c.Map502[k] = 0
			c.Map503[k] = 0
			c.Map504[k] = 0
		}

		//统计多少个去重IP
		vi, ok := c.MapIp[k]
		if ok {
			//_, ok2 := IpMap[log.RemoteAddr]
			_, ok2 := IpMap[log.XRealIP]
			if ok2 {
				c.MapIp[k] = vi + 0
			} else {
				//IpMap[log.RemoteAddr] = "1"
				IpMap[log.XRealIP] = "1"
				c.MapIp[k] = vi + 1
			}
		} else {
			c.MapIp[k] = 0
			IpMap = make(map[string]string)
		}

		//统计字节
		v, ok = c.MapB[k]
		if ok {
			c.MapB[k] = v + log.BodyBytes
		} else {
			c.MapB[k] = log.BodyBytes
		}
	}
	vt, ok := c.MapT[k]
	if ok {
		c.MapT[k] = vt + log.TimeSeconds
	} else {
		c.MapT[k] = vt
	}

	mt, ok := c.MapMaxT[k]
	if ok {
		if log.TimeSeconds > mt {
			c.MapMaxT[k] = log.TimeSeconds
		}
	} else {
		c.MapMaxT[k] = log.TimeSeconds
	}

}

func PrintBar(v float64, min float64, max float64) {

	n := int(100.0 * (v - min) / (max - min))

	x := n / 2
	y := n % 2
	var buffer bytes.Buffer
	for i := 0; i < x; i++ {
		buffer.WriteString("+")
	}
	if y > 0 {
		buffer.WriteString("-")
	}
	if min*3.0 < v {
		color.Red(buffer.String())
	} else {
		fmt.Print(buffer.String())
	}
	fmt.Println()
}

func (c *TrendCounter) Print(tendargs string) {
	//var i int64
	var min float64 = 3600.0
	var max float64 = 0.0

	minutes := make([]string, 0)

	for i, _ := range c.MapT {
		minutes = append(minutes, i)
		t, ok := c.MapT[i]
		if ok {
			cc, _ := c.MapC[i]
			at := t / float64(cc)
			if min > at {
				min = at
			}
			if max < at {
				max = at
			}
		}
	}

	sort.Strings(minutes)

	for _, i := range minutes {
		vc, _ := c.MapC[i]
		vb, _ := c.MapB[i]
		vt, _ := c.MapT[i]
		mt, _ := c.MapMaxT[i]
		cip, _ := c.MapIp[i]
		s200, _ := c.Map200[i]
		s301, _ := c.Map301[i]
		s302, _ := c.Map302[i]
		s400, _ := c.Map400[i]
		s403, _ := c.Map403[i]
		s404, _ := c.Map404[i]
		s499, _ := c.Map499[i]
		s500, _ := c.Map500[i]
		s502, _ := c.Map502[i]
		s503, _ := c.Map503[i]
		s504, _ := c.Map504[i]

		if tendargs == "sc" {
			color.Cyan("%s\t", i)
			color.Yellow("%d\t", vc)
			color.Red("%d\t", cip)
			color.Green("%f\t", vt/float64(vc))
			fmt.Printf("%f\t%f\t", mt, float64(vb)/1024/1024)
			color.Red("%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\n", s200, s301, s302, s400, s403, s404, s499, s500, s502, s503, s504)
		} else if tendargs == "ua" {
			Baiduspider, _ := c.MapBaiduspider[i]
			Spider360, _ := c.MapSpider360[i]
			Sogouspider, _ := c.MapSogouspider[i]
			Googlebot, _ := c.MapGooglebot[i]
			Sosospider, _ := c.MapSosospider[i]
			YisouSpider, _ := c.MapYisouSpider[i]

			UCBrowser, _ := c.MapUCBrowser[i]
			MicroMessenger, _ := c.MapMicroMessenger[i]
			MQQBrowser, _ := c.MapMQQBrowser[i]
			Maxthon, _ := c.MapMaxthon[i]
			QQBrowser, _ := c.MapQQBrowser[i]
			LBBROWSER, _ := c.MapLBBROWSER[i]
			SE360, _ := c.MapSE360[i]

			msie, _ := c.Mapmsie[i]
			chrome, _ := c.Mapchrome[i]
			firefox, _ := c.Mapfirefox[i]
			safari, _ := c.Mapsafari[i]
			OtherUa, _ := c.MapOtherUa[i]

			color.Cyan("%s\t", i)
			color.Yellow("%d\t", vc)
			//color.Red("%d\t", cip)
			//color.Green("%f\t", vt/float64(vc))
			//fmt.Printf("%f\t%f\t", mt, float64(vb)/1024/1024)
			color.Red("%d\t%d\t%d\t%d\t%d\t%d\t", Baiduspider, Spider360, Sogouspider, Googlebot, Sosospider, YisouSpider)
			color.Yellow("%d\t%d\t%d\t", UCBrowser, MicroMessenger, MQQBrowser)
			color.Green("%d\t%d\t%d\t%d\t", Maxthon, QQBrowser, LBBROWSER, SE360)
			color.Cyan("%d\t%d\t%d\t%d\t%d\n", msie, chrome, firefox, safari, OtherUa)
		} else if len(tendargs) > 4 {
			color.Cyan("%s\t", i)
			color.Yellow("%d\t", vc)
			uricount, _ := UriMap[i]
			sorted_keys := make([]string, 0)
			for kk, _ := range uricount {
				sorted_keys = append(sorted_keys, kk)
			}

			sort.Strings(sorted_keys)

			for _, kk := range sorted_keys {
				color.Red("%d\t", uricount[kk])
			}
			color.Red("\n")
			//fmt.Println(UriMap[i])
		} else {
			color.Cyan("%s\t", i)
			color.Yellow("%d\t", vc)
			color.Red("%d\t", cip)
			color.Green("%f\t", vt/float64(vc))
			//fmt.Printf("%f\t%f\t", mt, float64(vb)/float64(vc))
			fmt.Printf("%f\t%f\t", mt, float64(vb)/1024/1024)
			color.Red("%d\t%d\t%d\t%d\t", s200, s301+s302, s400+s403+s404+s499, s500+s502+s503+s504)
			PrintBar(vt/float64(vc), min, max)
		}
	}
}

//打印非时间的特别的key排列
func (c *TrendCounter) Print2() {
	var rb ByCount = make([]CountItem, 0, len(c.MapC))
	for k, v := range c.MapC {
		rb = append(rb, *&CountItem{k, v})
	}
	sort.Sort(rb)
	for _, v := range rb {
		vc, _ := c.MapC[v.K]
		vb, _ := c.MapB[v.K]
		vt, _ := c.MapT[v.K]
		cip, _ := c.MapIp[v.K]
		s200, _ := c.Map200[v.K]
		s301, _ := c.Map301[v.K]
		s302, _ := c.Map302[v.K]
		s400, _ := c.Map400[v.K]
		s403, _ := c.Map403[v.K]
		s404, _ := c.Map404[v.K]
		s499, _ := c.Map499[v.K]
		s500, _ := c.Map500[v.K]
		s502, _ := c.Map502[v.K]
		s503, _ := c.Map503[v.K]
		s504, _ := c.Map504[v.K]
		color.Cyan("%80.80s\t", v.K)
		color.Yellow("%d\t", vc)
		color.Red("%d\t", cip)
		color.Green("%f\t", vt/float64(vc))
		fmt.Printf("%f\t", float64(vb)/1024/1024)
		color.Red("%d\t%d\t%d\t%d\n", s200, s301+s302, s400+s403+s404+s499, s500+s502+s503+s504)
	}
}
